#include "Shell_PCH.h"
#include "Shell.h"

/*--------------------------------------------------------------------------*/

IShell* g_Shell = NULL;

/*--------------------------------------------------------------------------*/

CShell::CShell() :
	m_luaState(NULL),
	IThread("ShellThread", 20.0f, EThread::SynchronizeBeforeRendering)
{
	m_functionsvec_mutex = g_Kernel->CreateNewMutex();
	m_commandsvec_mutex = g_Kernel->CreateNewMutex();
	m_luaState = luaL_newstate();	
	luabind::open(m_luaState);
	StartThread();
}

/*--------------------------------------------------------------------------*/

CShell::~CShell()
{
	lua_close(m_luaState);
	delete m_functionsvec_mutex;
	delete m_commandsvec_mutex;
}

/*--------------------------------------------------------------------------*/

void CShell::Command( const std::string& cmd )
{
	m_commandsvec_mutex->Lock();
	m_commandsVector.push_back(CMD(cmd, true));
	m_commandsvec_mutex->Unlock();
}

/*--------------------------------------------------------------------------*/

void CShell::File( const std::string& path )
{
	m_commandsvec_mutex->Lock();
	m_commandsVector.push_back(CMD(path, false));
	m_commandsvec_mutex->Unlock();
}

/*--------------------------------------------------------------------------*/

void CShell::FileNow( const std::string& path )
{
	int result = luaL_dofile(m_luaState, path.c_str());

	if (result != 0)
	{
		__Error("LUA ERROR:\n%s", lua_tostring(m_luaState, -1));
	}
}

/*--------------------------------------------------------------------------*/

int CShell::ThreadLoop()
{
	m_commandsvec_mutex->Lock();

	if (m_commandsVector.empty() == true)
	{
		m_commandsvec_mutex->Unlock();
		return 0;
	}
	else
	{
		for (auto iter = m_commandsVector.begin(); iter != m_commandsVector.end(); ++iter)
		{
			int result = 0;

			if (iter->m_isLine)
			{
				result = luaL_dostring(m_luaState, iter->m_cmd.c_str()); 
			}
			else
			{
				result = luaL_dofile(m_luaState, iter->m_cmd.c_str());
			}

			if (result != 0)
			{
				__Error("LUA ERROR:\n%s", lua_tostring(m_luaState, -1));
			}

		}
	}

	m_commandsVector.clear();
	m_commandsvec_mutex->Unlock();

	return 0;
}

/*--------------------------------------------------------------------------*/

void CShell::AddLuaFunction( const std::string& name, void (*ptn)(const std::string&, int, int, const std::string&) )
{
	luabind::module(m_luaState) [
		luabind::def(name.c_str(), ptn)
	];

	m_functionsvec_mutex->Lock();
	m_functionsVector.push_back(name);
	m_functionsvec_mutex->Unlock();
}

/*--------------------------------------------------------------------------*/

void CShell::AddLuaFunction( const std::string& name, void (*ptn)(const std::string&, const std::string&) )
{
	luabind::module(m_luaState) [
		luabind::def(name.c_str(), ptn)
	];

	m_functionsvec_mutex->Lock();
	m_functionsVector.push_back(name);
	m_functionsvec_mutex->Unlock();
}

/*--------------------------------------------------------------------------*/

void CShell::AddLuaFunction(const std::string& name, void (*ptn)(const std::string&))
{
	luabind::module(m_luaState) [
		luabind::def(name.c_str(), ptn)
	];

	m_functionsvec_mutex->Lock();
	m_functionsVector.push_back(name);
	m_functionsvec_mutex->Unlock();
}

/*--------------------------------------------------------------------------*/

void CShell::AddLuaFunction( const std::string& name, void (*ptn)() )
{
	luabind::module(m_luaState) [
		luabind::def(name.c_str(), ptn)
	];

	m_functionsvec_mutex->Lock();
	m_functionsVector.push_back(name);
	m_functionsvec_mutex->Unlock();
}

/*--------------------------------------------------------------------------*/

void CShell::AddLuaFunction( const std::string& name, void (*ptn)(float, float, float, float, char, float) )
{
	luabind::module(m_luaState) [
		luabind::def(name.c_str(), ptn)
	];

	m_functionsvec_mutex->Lock();
	m_functionsVector.push_back(name);
	m_functionsvec_mutex->Unlock();	
}

/*--------------------------------------------------------------------------*/

void CShell::CallFunction( const std::string& name )
{
	luabind::call_function<int>(m_luaState, name.c_str());
}

/*--------------------------------------------------------------------------*/

void CShell::OnThreadStart()
{

}

/*--------------------------------------------------------------------------*/

CMD::CMD( const std::string& cmd, bool isLine ) :
	m_cmd(cmd),
	m_isLine(isLine)
{

}

/*--------------------------------------------------------------------------*/